package org.abc.fund.service.funds;

import org.abc.fund.dto.*;
import org.abc.fund.entity.funds.*;
import org.abc.fund.repository.funds.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class FundProfileService {

    @Autowired private FundBasicInfoRepository basicInfoRepo;
    @Autowired private FundNetValueHistoryRepository netValueRepo;
    @Autowired private FundTagRelationRepository tagRepo;
    @Autowired private FundHoldingRepository holdingRepo;
    @Autowired private FundAnnouncementRepository announcementRepo;

    public FundProfileDTO getProfile(String code) {
        FundBasicInfo fund = basicInfoRepo.findById(code).orElse(null);
        if (fund == null) return null;

        FundProfileDTO dto = new FundProfileDTO();

        // 基本信息
        FundBasicInfoDTO basicInfoDTO = new FundBasicInfoDTO(
                fund.getCode(), fund.getName(), fund.getType(), fund.getStatus(),
                fund.getLatestNav(), fund.getLatestNavDate(),
                fund.getLatestEstNav(), fund.getLatestEstRate(),
                fund.getManager() != null ? fund.getManager().getName() : null,
                fund.getCompany() != null ? fund.getCompany().getName() : null
        );
        dto.setBasicInfo(basicInfoDTO);

        // 净值历史
        List<NetValueDTO> netValues = netValueRepo.findByFundCodeOrderByNetDateDesc(code).stream()
                .limit(60)
                .map(h -> new NetValueDTO(
                        h.getNetDate().toString(),
                        h.getUnitNav() != null ? h.getUnitNav().doubleValue() : 0.0
                )).collect(Collectors.toList());
        dto.setNetValueHistory(netValues);

        // 标签
        List<String> tags = tagRepo.findByFundCode(code).stream()
                .map(tr -> tr.getTag().getName())
                .collect(Collectors.toList());
        dto.setTags(tags);

        // 持仓
        List<HoldingDTO> holdings = holdingRepo.findByFundCodeOrderByHoldingRatioDesc(code).stream()
                .map(h -> new HoldingDTO(h.getStockName(),
                        h.getHoldingRatio() != null ? h.getHoldingRatio().doubleValue() : 0.0))
                .collect(Collectors.toList());
        dto.setHoldings(holdings);

        // 公告
        String latestAnnouncement = announcementRepo.findTop1ByFundCodeOrderByPublishDateDesc(code)
                .map(FundAnnouncement::getContent)
                .orElse("暂无公告");
        dto.setAnnouncementContent(latestAnnouncement);

        // 业绩
        FundPerformanceDTO performance = computePerformance(code, netValues);
        dto.setPerformance(performance);

        return dto;
    }

    private FundPerformanceDTO computePerformance(String code, List<NetValueDTO> history) {
        FundPerformanceDTO dto = new FundPerformanceDTO();
        dto.setCode(code);
        if (history.size() < 2) return dto;

        double latest = history.get(0).unitNav();
        double earliest = history.get(history.size() - 1).unitNav();

        dto.setAnnualReturn(Math.pow(latest / earliest, 1.0) - 1); // 实际应除以年数
        dto.setMaxDrawdown(estimateMaxDrawdown(history));
        dto.setSharpeRatio(estimateSharpeRatio(history));
        dto.setStddev(estimateStdDev(history));

        // 可选：近1年、3年收益估算（这里简化为30日为月）
        if (history.size() >= 252) {
            double nav1Y = history.get(252).unitNav(); // 大约一年前
            dto.setReturn1Y((latest - nav1Y) / nav1Y);
        }
        if (history.size() >= 756) {
            double nav3Y = history.get(756).unitNav(); // 大约三年前
            dto.setReturn3Y((latest - nav3Y) / nav3Y);
        }

        return dto;
    }

    private double estimateMaxDrawdown(List<NetValueDTO> history) {
        double max = Double.MIN_VALUE, maxDrawdown = 0.0;
        for (NetValueDTO h : history) {
            double nav = h.unitNav();
            if (nav > max) max = nav;
            double drawdown = (max - nav) / max;
            maxDrawdown = Math.max(maxDrawdown, drawdown);
        }
        return maxDrawdown;
    }

    private double estimateSharpeRatio(List<NetValueDTO> history) {
        double avg = history.stream().mapToDouble(NetValueDTO::unitNav).average().orElse(1.0);
        double std = estimateStdDev(history);
        return std > 0 ? (avg - 1) / std : 0;
    }

    private double estimateStdDev(List<NetValueDTO> history) {
        double avg = history.stream().mapToDouble(NetValueDTO::unitNav).average().orElse(1.0);
        double variance = history.stream()
                .mapToDouble(h -> Math.pow(h.unitNav() - avg, 2))
                .average().orElse(0);
        return Math.sqrt(variance);
    }

}
